﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.ServiceModel.Channels;
using System.Threading;
using Kugar.Core.BaseStruct;
using Kugar.Core.Collections;
using Kugar.Core.ExtMethod;

namespace Kugar.Core.Communications.Transfer
{
    public class UDPTransfer : TransferBase, INetTransfer
    {
        protected Socket _socket = null;
        protected bool _isOwner = false;
        protected bool isClosed = false;
        protected BufferManager bufferManager = null;
        protected int _localPort;
        protected EndPoint _remotePoint;
        private object lockerObj = new object();
        protected Dictionary<int, UDPSendCheckInfo> cacheSendedItem = new Dictionary<int, UDPSendCheckInfo>();
        protected Dictionary<int, UDPReceiveCheckInfo> cacheRevItem = new Dictionary<int, UDPReceiveCheckInfo>();
        private int _receiveBufferCount = 8192;
        private bool _isAutoReceive = true;
        private bool _isStop = false;
        protected bool _isEnableSendCheck = false;
        private TimerEx timerSendChecker = null;
        private int _remoteRevBuffer = 1024;

        public UDPTransfer(Socket socket, IPEndPoint remotePoint, int receiveDataMaxLength, bool isEnableSendCheck, bool isOwner)
            : this(socket, remotePoint, receiveDataMaxLength, isEnableSendCheck, isOwner, true)
        {
            //receiveDataMaxLength += 100;

            //bufferManager = BufferManager.CreateBufferManager(receiveDataMaxLength*1024, receiveDataMaxLength);

            //_socket = socket;

            //var tempBuffer = bufferManager.TakeBuffer(_receiveBufferCount);

            //_socket.BeginReceiveFrom(tempBuffer, 0, _receiveBufferCount, SocketFlags.None, ref remotePoint,
            //                         OnDataReceive, tempBuffer);
        }

        internal UDPTransfer(Socket socket, IPEndPoint remotePoint, int receiveDataMaxLength,bool isEnableSendCheck, bool isOwner, bool isAutoReceive)
        {
            if (remotePoint == null)
            {
                throw new ArgumentNullException("remotePoint");
            }

            _isOwner = isOwner;
            _socket = socket;
            _remotePoint = remotePoint;
            _ipRemotePint = (IPEndPoint)remotePoint;
            _receiveBufferCount = Math.Min(socket.ReceiveBufferSize, receiveDataMaxLength+50);
            _isAutoReceive = isAutoReceive;
            _localPort = ((IPEndPoint)_socket.LocalEndPoint).Port;

            OnBeginReceive();

            if (_isAutoReceive || isEnableSendCheck)
            {
                _receiveBufferCount += 100;

                bufferManager = BufferManager.CreateBufferManager(_receiveBufferCount * 1024, _receiveBufferCount);

            }

            if (isAutoReceive)
            {
                OnBeginReceive();
            }

            //timerSendChecker = new TimerEx(OnSendCheckerTimer, 2000, null);

            EnableSendCheck = isEnableSendCheck;

            //if (isAutoReceive)
            //{
            //    _receiveBufferCount += 100;

            //    bufferManager = BufferManager.CreateBufferManager(_receiveBufferCount * 1024, _receiveBufferCount);

            //    _localPort = ((IPEndPoint)socket.LocalEndPoint).Port;

            //    var tempBuffer = bufferManager.TakeBuffer(_receiveBufferCount);

            //    _socket.BeginReceiveFrom(tempBuffer, 0, _receiveBufferCount, SocketFlags.None, ref _remotePoint,
            //                             OnDataReceive, tempBuffer);
            //}

        }

        public bool EnableSendCheck
        {
            get { return _isEnableSendCheck; }
            set
            {
                _isEnableSendCheck = value;

                if (value)
                {
                    //timerSendChecker.Start();
                }
            }
        }

        public int RemoteRevBuffer { set; get; }

        private void OnDataReceive(IAsyncResult iar)
        {
            int receiveCount = 0;
            Exception error = null;
            try
            {
                receiveCount = _socket.EndReceiveFrom(iar, ref _remotePoint);
            }
            catch (Exception ex)
            {
                error = ex;
            }

            if (receiveCount <= 0)
            {
                return;
            }

            if (error == null && !isClosed && !_isStop)
            {
                OnBeginReceive();
            }



            var buff = (byte[])iar.AsyncState;

            var decodeResult = DecodeReceiveData(buff, 0, receiveCount);

            if (decodeResult.Array != null && decodeResult.Count > 0)
            {
                //var response = getResponseData(new ArraySegment<byte>(buff, 0, receiveCount));

                //if (response.Count > 0)
                //{

                //}

                //OnAfterReceiveData(decodeResult, error);

                OnReceiveDataInternal(decodeResult);
            }

            if (decodeResult.Array != buff && decodeResult.Count > 0)
            {
                bufferManager.ReturnBuffer(decodeResult.Array);
            }

            bufferManager.ReturnBuffer(buff);
        }

        private static ArraySegment<byte> emptyData = new ArraySegment<byte>();

        protected void OnReceiveDataInternal(ArraySegment<byte> data)
        {
            if (!_isEnableSendCheck)
            {
                OnAfterReceiveData(data, null);

                return;
            }

            //如果crc校验不通过，则直接丢弃
            if (data.Array.GetCRCCode(data.Offset, data.Count) != 0)
            {
                return;
            }

            var bagID = BitConverter.ToInt32(data.Array, 0);

            ArraySegment<byte> responseData = emptyData;

            //if (data.Array[2]==0xFF) //接收方取消数据包发送
            //{
            //    sendInfo.Callback(new Exception("接收方取消该数据包的接收"));
            //    OnAfterSendData(sendInfo.Data,0,new Exception("接收方取消该数据包的接收"));
            //    return;
            //}

            var isComplate = false;
            Exception error = null;
            var sendTime = 1;

            var dataBagFlag = data.Array[4];

            if (dataBagFlag == 0x01 || dataBagFlag == 0x03) //接收到发送方开始发送数据或者最后一个包
            {
                responseData = getRevResponse(data, ref isComplate, ref error);
                sendTime = 1;

                if (isComplate)
                {
                    var revInfo = cacheRevItem.TryGetValue(bagID);

                    OnAfterReceiveData(revInfo.Data, error);

                    //cacheRevItem.Remove(bagID);

                    bufferManager.ReturnBuffer(revInfo.Data.Array);

                    revInfo.Data = emptyData;

                    revInfo.isCompleted = true;

                }
            }
            else if (dataBagFlag == 0x02 || dataBagFlag == 0x04)  //如果是ACK应答包，则发送下一个数据包
            {
                if (dataBagFlag == 0x04)
                {
                    isComplate = true;
                }
                else
                {
                    responseData = getSendResponse(data, ref isComplate, ref error);
                }

                

                if (isComplate)
                {
                    var sendInfo = cacheSendedItem.TryGetValue(bagID);

                    if (sendInfo==null)
                    {
                        return;
                    }

                    cacheSendedItem.Remove(bagID);

                    var sendCount = sendInfo.CurrentSendedPos - sendInfo.Data.Offset;

                    if (sendInfo.Callback != null)
                    {
                        sendInfo.Callback(this,new DataAfterSendEventArgs(sendInfo.Data,sendCount,error,sendInfo.AsyncState));
                    }

                    OnAfterSendData(sendInfo.Data, sendCount,error);

                    bufferManager.ReturnBuffer(sendInfo.Data.Array);
                    sendInfo.Callback = null;
                    sendInfo.AsyncState = null;
                }
            }
            else if (dataBagFlag == 0xF1 || dataBagFlag == 0xF2 || dataBagFlag == 0xF3)
            {
                responseData = getHandShakeResponse(data);
            }

            if (responseData != emptyData)
            {
                var auto = new AutoResetEvent(false);

                for (int i = 0; i < sendTime; i++)
                {
                    SendDataAsync(responseData.Array, responseData.Offset, responseData.Count, (s1, e1) =>
                                                                                                   {
                                                                                                       auto.Set();
                                                                                                   }, null);

                    auto.WaitOne(20000);
                }

                bufferManager.ReturnBuffer(responseData.Array);

            }
        }

        //接收到接收方的ACK应答包, 作为发送方的应答包
        protected virtual ArraySegment<byte> getSendResponse(ArraySegment<byte> data, ref bool isComplate, ref Exception error)
        {
            var bagID = BitConverter.ToInt32(data.Array, 0);
            var sendInfo = cacheSendedItem.TryGetValue(bagID);

            if (sendInfo == null)
            {
                return emptyData;
            }

            var bagIndex = BitConverter.ToInt16(data.Array, 5);
            short currentBagIndex = 0;
            int currentDataPos = 0;
            int readCount = 0;

            lock (sendInfo)
            {
                if (bagIndex != sendInfo.CurrentSendedBagIndex)
                {
                    return emptyData;
                }
                else
                {
                    currentBagIndex = sendInfo.CurrentSendedBagIndex;
                    currentDataPos = sendInfo.CurrentSendedPos;
                    //sendInfo.CurrentSendedBagIndex++;
                }
            }

            if (bagIndex==0)
            {
                var tempRevBuff = BitConverter.ToInt32(data.Array, 7);
                sendInfo.RevBufferLength = tempRevBuff;
            }
            

            readCount = Math.Min(sendInfo.RevBufferLength, sendInfo.Data.Count + sendInfo.Data.Offset - currentDataPos);
            currentBagIndex++;

            sendInfo.CurrentSendedPos=currentDataPos+ readCount;
            sendInfo.CurrentSendedBagIndex = currentBagIndex;

            if (readCount<=0)
            {
                isComplate = true;
                error = null;
                return emptyData;
            }

            if (bagIndex>0 && sendInfo.Data.Offset + (bagIndex - 1) * sendInfo.RevBufferLength >= sendInfo.Data.Count + sendInfo.Data.Offset)
            {
                isComplate = true;
                error = null;
                return emptyData;
            }

            try
            {
                //sendInfo.CurrentSendedBagIndex = currentBagIndex;

                return buildSendDataByDataBagIndex(sendInfo, currentBagIndex);
            }
            catch(Exception ex)
            {
                isComplate = true;
                error = ex;
                return emptyData;
            }
            //if (readCount <= 0)
            //{
            //    //TODO:发送完毕
            //    return emptyData;
            //}

            //var tempBuff = bufferManager.TakeBuffer(7 + readCount);

            //tempBuff[0] = data.Array[0];  //BagID
            //tempBuff[1] = data.Array[1];
            //tempBuff[2] = 0x01;              //Flag

            //BitConverter.GetBytes(currentBagIndex + 1).CopyTo(tempBuff, 3); //BagIndex

            //Array.Copy(sendInfo.Data.Array, currentDataPos, tempBuff, 5, readCount);  //DataBlock

            //tempBuff.GetCRCCodeBytes(0, 5 + readCount).CopyTo(tempBuff, 5 + readCount);

            //return new ArraySegment<byte>(tempBuff, 0, 7 + readCount);
        }

        protected ArraySegment<byte> buildSendDataByDataBagIndex(UDPSendCheckInfo sendInfo,int bagIndex)
        {
            if (bagIndex==0)
            {
                var tempBuff = bufferManager.TakeBuffer(13);

                BitConverter.GetBytes(sendInfo.ID).CopyTo(tempBuff, 0);
                tempBuff[3] = 0x01;              //Flag
                BitConverter.GetBytes(bagIndex).CopyTo(tempBuff,5);
                BitConverter.GetBytes(sendInfo.Data.Count).CopyTo(tempBuff,7);
                tempBuff.GetCRCCodeBytes(0, 11).CopyTo(tempBuff, 11);

                return new ArraySegment<byte>(tempBuff,0,13);
            }
            else
            {
                var currentDataPos = sendInfo.Data.Offset+(bagIndex - 1) * sendInfo.RevBufferLength;
                var readCount = Math.Min(sendInfo.RevBufferLength, sendInfo.Data.Count + sendInfo.Data.Offset - currentDataPos);

                if (readCount<=0)
                {
                    throw new ArgumentOutOfRangeException("bagIndex");
                }

                var tempBuff = bufferManager.TakeBuffer(9 + readCount);

                BitConverter.GetBytes(sendInfo.ID).CopyTo(tempBuff, 0);
                
                if (currentDataPos+readCount>=sendInfo.Data.Count+sendInfo.Data.Offset)
                {
                    tempBuff[3] = 0x03;  //最后一个数据包
                }
                else
                {
                    tempBuff[3] = 0x01;              //Flag
                }

                BitConverter.GetBytes(bagIndex).CopyTo(tempBuff, 5); //BagIndex

                Array.Copy(sendInfo.Data.Array, currentDataPos, tempBuff, 7, readCount);  //DataBlock

                tempBuff.GetCRCCodeBytes(0, 7 + readCount).CopyTo(tempBuff, 7 + readCount);

                return new ArraySegment<byte>(tempBuff, 0, 9 + readCount);
            }
        }

        //作为接收方的应答包
        protected virtual ArraySegment<byte> getRevResponse(ArraySegment<byte> data, ref bool isComplate, ref Exception error)
        {
            var bagID = BitConverter.ToInt32(data.Array, 0);
            var bagIndex = BitConverter.ToInt16(data.Array, 5);

            if (!cacheRevItem.ContainsKey(bagID))
            {
                if (bagIndex == 0)
                {
                    var bagTotalLength = BitConverter.ToInt32(data.Array, 7);

                    var tempBuff = bufferManager.TakeBuffer(bagTotalLength);

                    var t = new UDPReceiveCheckInfo();
                    t.Data = new ArraySegment<byte>(tempBuff, 0, bagTotalLength);
                    t.CurrentRevedBagIndex = 0;
                    t.ID = bagID;
                    t.CurrentBufferPos = 0;
                    t.LastRevTime = DateTime.Now;
                    t.CurrentRevedBagIndex = 0;
                    cacheRevItem.Add(bagID, t);

                    var responseBuff = bufferManager.TakeBuffer(13);

                    responseBuff[0] = data.Array[0];
                    responseBuff[1] = data.Array[1];
                    responseBuff[2] = data.Array[2];
                    responseBuff[3] = data.Array[3];
                    responseBuff[4] = 0x02;
                    responseBuff[5] = 0x00;
                    responseBuff[6] = 0x00;

                    try
                    {
                        Array.Copy(BitConverter.GetBytes(_receiveBufferCount), 0, responseBuff, 5, 4);
                    }
                    catch (Exception)
                    {
                        
                        throw;
                    }
                    

                    var crcCode = responseBuff.GetCRCCode(0, 9);

                    Array.Copy(BitConverter.GetBytes(crcCode), 0, responseBuff, 9, 2);

                    return new ArraySegment<byte>(responseBuff, 0, 11);             
                }
            }
            else
            {

                var revInfo = cacheRevItem[bagID];

                if (revInfo==null && bagIndex==1)
                {
                    
                }

                if (bagIndex == revInfo.CurrentRevedBagIndex + 1)
                {
                    var revDataCount = data.Count - 7;

                    lock (revInfo)
                    {
                        if (!revInfo.isCompleted)
                        {
                            revInfo.CurrentRevedBagIndex++;
                            Array.Copy(data.Array, 5, revInfo.Data.Array, revInfo.CurrentBufferPos, revDataCount);
                            revInfo.CurrentBufferPos += (short)revDataCount;                            
                        }
                    }

                    if (data.Array[2]==0x03)
                    {
                        revInfo.isCompleted = true;
                        isComplate = true;
                        error = null;
                    }

                    //if (revInfo.CurrentBufferPos==revInfo.Data.Offset+revInfo.Data.Count)
                    //{
                        
                    //}

                    var tempBuffer = bufferManager.TakeBuffer(7);

                    tempBuffer[0] = data.Array[0];  //BagID
                    tempBuffer[1] = data.Array[1];

                    if (data.Array[2] == 0x03)
                    {
                        revInfo.isCompleted = true;
                        isComplate = true;
                        error = null;
                        tempBuffer[2] = 0x04;              //BagType:  02-应答包
                    }
                    else
                    {
                        tempBuffer[2] = 0x02;              //BagType:  02-应答包
                    }
                    
                    tempBuffer[3] = data.Array[3];  //包序号
                    tempBuffer[4] = data.Array[4];

                    tempBuffer.GetCRCCodeBytes(0, 5).CopyTo(tempBuffer, 5);



                    //Array.Copy(tempBuffer.GetCRCCodeBytes(0, 5),0,tempBuffer,5,2);

                    return new ArraySegment<byte>(tempBuffer, 0, 7);
                }
                else if (bagIndex != revInfo.CurrentRevedBagIndex)
                {
                    return emptyData;
                }


            }

            return emptyData;
        }

        //作为连接发起方的处理
        protected virtual ArraySegment<byte> getHandShakeResponse(ArraySegment<byte> data)
        {
            return emptyData;
        }

        private void OnBeginReceive()
        {
            if (_isAutoReceive && !_isStop)
            {
                var tempBuffer = bufferManager.TakeBuffer(_receiveBufferCount);

                _socket.BeginReceiveFrom(tempBuffer, 0, _receiveBufferCount, SocketFlags.None, ref _remotePoint,
                                         OnDataReceive, tempBuffer);
            }
        }

        private void OnSendCheckerTimer(object state)
        {
            
            if (cacheSendedItem.Count > 0)
            {
#if DEBUG

                var timeOutTime = DateTime.Now.AddSeconds(-120);
#else
                var timeOutTime = DateTime.Now.AddSeconds(-4);
#endif
                var itemList =new UDPSendCheckInfo[cacheSendedItem.Count];

                cacheSendedItem.Values.CopyTo(itemList,0);

                foreach (var info in itemList)
                {
                    if (info.LastSendTime< timeOutTime)
                    {
                        if (info.SendedCount >= 6)  //如果重发次数超过6次，则判定该数据包发送失败
                        {
                            //info.Callback(new TimeoutException());
                            cacheSendedItem.Remove(info.ID);
                        }
                        else
                        {
                            try
                            {
                                var t = buildSendDataByDataBagIndex(info, info.CurrentSendedBagIndex);
                                info.SendedCount++;
                                ThreadPool.QueueUserWorkItem(ResendItem, t);
                            }
                            catch (Exception)
                            {
                            
                            }
                        }
                    }
                }
            }


            if (cacheRevItem.Count>0)
            {
                var revItems =new UDPReceiveCheckInfo[cacheRevItem.Values.Count];
                cacheRevItem.Values.CopyTo(revItems,0);

#if DEBUG

                var timeOutTime = DateTime.Now.AddSeconds(-120);
#else
                var timeOutTime = DateTime.Now.AddSeconds(-10);
#endif

                //var timeOutTime = DateTime.Now.AddSeconds(-10);
                foreach (var revItem in revItems)
                {
                    if (revItem.LastRevTime < timeOutTime)
                    {
                        cacheRevItem.Remove(revItem.ID);
                    }
                }
            }
        }

        private void ResendItem(object state)
        {
            var t = (ArraySegment<byte>) state;

            SendDataAsync(t.Array, t.Offset, t.Count, null, null);
        }

        protected virtual ArraySegment<byte> DecodeReceiveData(byte[] sendStruct, int offset, int count)
        {
            //if (_isEnableSendCheck)
            //{
            //    if (sendStruct[offset] == 0x5A && sendStruct[offset + 1] == 0xA5 && sendStruct.GetCRCCode(offset, count) == 0)
            //    {
            //        if (sendStruct[offset + 2] == 0x02)
            //        {
            //            var id = BitConverter.ToInt32(sendStruct, offset + 3);

            //            UDPSendCheckInfo info = cacheSendedItem.TryGetValue(id, null);

            //            if (info == null)
            //            {
            //                return new ArraySegment<byte>(emptyData, 0, 0);
            //            }
            //            else
            //            {
            //                info.callback(info.EventArgs);
            //                OnAfterSendData(info.EventArgs.SendedData, count, null);
            //            }
            //        }
            //        else
            //        {
            //            return new ArraySegment<byte>(sendStruct, offset, count);
            //        }
            //    }
            //}
            //else
            //{
                return new ArraySegment<byte>(sendStruct, offset, count);
            //}
        }

        #region Overrides of TransferBase

        protected override void OnClose()
        {
            lock (lockerObj)
            {
                isClosed = true;

                timerSendChecker.Dispose();

                if (_isOwner)
                {
                    try
                    {
                        _socket.Shutdown(SocketShutdown.Both);
                    }
                    catch (Exception)
                    {

                    }

                    try
                    {
                        _socket.Close();
                    }
                    catch (Exception)
                    {

                    }
                }

                if (cacheSendedItem.Count > 0)
                {
                    var itemList = new UDPSendCheckInfo[cacheSendedItem.Count];

                    cacheSendedItem.Values.CopyTo(itemList, 0);

                    foreach (var info in itemList)
                    {
                        bufferManager.ReturnBuffer(info.Data.Array);
                        info.Callback = null;
                        info.AsyncState = null;
                    }

                    cacheSendedItem.Clear();
                }


                if (cacheRevItem.Count > 0)
                {
                    var revItems = new UDPReceiveCheckInfo[cacheRevItem.Values.Count];
                    cacheRevItem.Values.CopyTo(revItems, 0);

                    foreach (var revItem in revItems)
                    {
                        bufferManager.ReturnBuffer(revItem.Data.Array);
                    }

                    cacheRevItem.Clear();
                }

                if (bufferManager != null)
                {
                    bufferManager.Clear();
                    bufferManager = null;
                }
            }


        }

        protected override bool OnStart()
        {
            if (!_isStop)
            {
                return false;
            }
            else
            {
                _isStop = false;

                if (_isEnableSendCheck)
                {
                    timerSendChecker.Start();
                }

                OnBeginReceive();
                return true;
            }

            //throw new NotImplementedException();
        }

        protected override bool OnStop()
        {
            if (!_isStop)
            {
                _isStop = true;
                timerSendChecker.Stop();
                return true;
            }
            else
            {
                //_isStop = false;
                return false;
                //OnBeginReceive();
            }
        }

        public override bool IsStop
        {
            get { return _isStop; }
        }

        public override int ReceiveBufferCount
        {
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(@"value");
                }

                Interlocked.Exchange(ref _receiveBufferCount, value);
            }
            get { return _receiveBufferCount; }

        }

        public override bool IsActivity
        {
            get { return true; }
        }

        //public override void SendAsyn(byte[] sendStruct, int offset, int count)
        //{
        //    var buffCount = count + 4 + 2;

        //    var buff = bufferManager.TakeBuffer(buffCount);

        //    //数据包编号
        //    var lockerItem = autoEventPool.GetLockItem();

        //    Array.Copy(BitConverter.GetBytes(lockerItem.ID), 0, buff, 0, 4);
        //    Array.Copy(sendStruct, offset, buff, 4, count);

        //    var crcCode = buff.GetCRCCode(0, buffCount - 2);

        //    Array.Copy(BitConverter.GetBytes(crcCode), 0, buff, 4 + count, 2);

        //    cacheDataBag.Add(lockerItem.ID);

        //    base.SendAsyn(sendStruct, offset, count);

        //}

        public override void SendAsync(byte[] sendStruct, int offset, int count, EventHandler<DataAfterSendEventArgs> callback, object state)
        {
            if (isClosed || _isStop)
            {
                return;
            }

            var codeSend = CodeSendData(sendStruct, offset, count);

            if (_isEnableSendCheck)
            {
                var infoItem = new UDPSendCheckInfo();
                var id = RandomEx.Next();

                infoItem.Data = codeSend;
                infoItem.CurrentSendedBagIndex = 0;
                infoItem.AsyncState = state;
                infoItem.ID = (short)id;
                infoItem.Callback = callback;
                infoItem.AsyncState = state;

                //var requestBufferCount = codeSend.Count + 9;
                var tempBuff = bufferManager.TakeBuffer(11);

                ByteStream bs = new ByteStream(tempBuff, 0, 11);

                bs.Write(BitConverter.GetBytes(infoItem.ID));  //BagID-2
                bs.WriteByte(0x01); //Flag=0x01 为发送方发送的数据包-1
                bs.Write(BitConverter.GetBytes((short)0)); //BagIndex-2
                bs.Write(BitConverter.GetBytes(codeSend.Count));  //数据包总大小-4

                var crcCode = tempBuff.GetCRCCode(0, 9); //-2

                bs.Write(BitConverter.GetBytes(crcCode));

                codeSend = new ArraySegment<byte>(tempBuff, 0, 11);

                infoItem.LastSendTime = DateTime.Now;

                cacheSendedItem.Add(infoItem.ID, infoItem);

            }

            SendDataAsync(codeSend.Array, codeSend.Offset, codeSend.Count,
                                            (s1, e1) =>
                                            {
                                                if (!_isEnableSendCheck)
                                                {
                                                    //var ev = new DataAfterSendEventArgs(new ArraySegment<byte>(sendStruct, offset, count),
                                                    //                                             e1.SendCount, e1.Error, state);

                                                    if (callback!=null)
                                                    {
                                                        callback(this, e1);
                                                    }

                                                    OnAfterSendData(e1.SendedData, e1.SendCount, e1.Error);
                                                }
                                            }, state);

        }

        protected override void SendDataAsync(byte[] sendStruct, int offset, int count, EventHandler<DataAfterSendEventArgs> eventHandler, object state)
        {
            if (isClosed)
            {
                return;
            }

            _socket.BeginSendTo(sendStruct, offset, count, SocketFlags.None, _remotePoint,
                                            (iar) =>
                                            {
                                                int sendCount = 0;
                                                Exception error = null;
                                                try
                                                {
                                                    sendCount = _socket.EndSendTo(iar);
                                                }
                                                catch (Exception ex)
                                                {
                                                    error = ex;
                                                }

                                                if (!_isEnableSendCheck)
                                                {
                                                    var ev = new DataAfterSendEventArgs(new ArraySegment<byte>(sendStruct, offset, count),
                                                                                                            sendCount, error, state);
                                                    Events.EventHelper.Raise(eventHandler, this, ev);
                                                    OnAfterSendData(ev.SendedData, sendCount, error);
                                                }
                                                //else
                                                //{
                                                //    UDPSendCheckInfo infoItem = null;

                                                //    infoItem = cacheSendedItem.TryGetValue(id);

                                                //    if (infoItem==null)
                                                //    {
                                                //        infoItem=new UDPSendCheckInfo();

                                                //        infoItem.EventArgs = ev;
                                                //        infoItem.ID = id;

                                                //        cacheSendedItem.Add(id,infoItem);
                                                //    }


                                                //    infoItem.SendCount++;
                                                //    infoItem.SendTime = DateTime.Now;

                                                //}


                                            }, state);
            //au.WaitOne(_socket.SendTimeout);

            //if (error != null)
            //{
            //    throw error;
            //}


        }

        #endregion

        #region Implementation of INetTransfer

        public int LocalPort
        {
            get { return _localPort; }
            protected set { _localPort = value; }
        }

        private IPEndPoint _ipRemotePint = null;
        public IPEndPoint RemotePoint
        {
            get { return _ipRemotePint; }
            protected set
            {
                _remotePoint = value;
                _ipRemotePint = value;
            }
        }

        #endregion
    }

    public class UDPSendCheckInfo
    {
        public int ID;
        public ArraySegment<byte> Data;
        public short CurrentSendedBagIndex;
        public int RevBufferLength;
        public int CurrentSendedPos = 0;
        public DateTime LastSendTime;
        public int SendedCount = 0;
        public object AsyncState;
        public EventHandler<DataAfterSendEventArgs> Callback;
    }

    public class UDPReceiveCheckInfo
    {
        public int ID;
        public ArraySegment<byte> Data;
        public short CurrentRevedBagIndex;
        public short CurrentBufferPos;
        public DateTime LastRevTime;
        public bool isCompleted = false;
    }

    //public class UDPFactory
    //{
    //    //private Socket _socket = null;
    //    private UDPBroadcast _broadcastTransfer = null;
    //    private BufferManager bufferManager = null;
    //    private MutileKeysDictionary<int, EndPoint, UDPTransferInternal> cacheRemotePoint = new MutileKeysDictionary<int, EndPoint, UDPTransferInternal>();
    //    //private int _receiveBufferCount = 0;
    //    private bool isClosed = false;
    //    private int _broadcastPort = 0;
    //    private Dictionary<int, UdpSocketConfig> cacheSocket = new Dictionary<int, UdpSocketConfig>();
    //    private object lockerObj = new object();

    //    //public UDPFactory(int listenPort, int receiveDataMaxLength)
    //    //{
    //    //    //receiveDataMaxLength += 100;

    //    //    //bufferManager = BufferManager.CreateBufferManager(receiveDataMaxLength*1024,receiveDataMaxLength);

    //    //    //_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    //    //    //_socket.Bind(new IPEndPoint(IPAddress.Any, listenPort));


    //    //    //var tempBuff = bufferManager.TakeBuffer(receiveDataMaxLength);
    //    //    //EndPoint remotePoint = null;

    //    //    //var par = new UdpReceiveParam();
    //    //    //par.Buffer = tempBuff;
    //    //    //par.socket = _socket;

    //    //    //_socket.BeginReceiveFrom(tempBuff, 0, receiveDataMaxLength, SocketFlags.None, ref remotePoint, OnDataReceive, par);
    //    //}

    //    public void AddPort(int port, bool isEnableSendCheck, int maxLengthPerDataPack)
    //    {
    //        if (maxLengthPerDataPack <= 1024)
    //        {
    //            throw new ArgumentOutOfRangeException("maxLengthPerDataPack");
    //        }

    //        maxLengthPerDataPack += 100;

    //        if (cacheSocket.ContainsKey(port))
    //        {
    //            return;
    //        }

    //        lock (lockerObj)
    //        {
    //            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    //            socket.Bind(new IPEndPoint(IPAddress.Any, port));

    //            var t = new UdpSocketConfig();

    //            t.Port = port;
    //            t.Socket = socket;
    //            t.EnableSendCheck = isEnableSendCheck;
    //            t.InitMaxLengthPerDataPack = maxLengthPerDataPack;


    //            cacheSocket.Add(port, t);

    //            var tempBuff = bufferManager.TakeBuffer(maxLengthPerDataPack);
    //            EndPoint remotePoint = null;

    //            var par = new UdpReceiveParam();
    //            par.Buffer = tempBuff;
    //            par.socket = socket;
    //            par.InitMaxLengthPerDataPack = maxLengthPerDataPack;


    //            socket.BeginReceiveFrom(tempBuff, 0, maxLengthPerDataPack, SocketFlags.None, ref remotePoint, OnDataReceive, par);

    //            //socket.BeginReceive(OnAcceptedConnect, t);
    //        }
    //    }

    //    public void RemovePort(int port)
    //    {
    //        lock (lockerObj)
    //        {
    //            var config = cacheSocket.TryGetValue(port);

    //            if (config != null)
    //            {
    //                try
    //                {
    //                    config.Socket.Shutdown(SocketShutdown.Both);
    //                }
    //                catch (Exception)
    //                {
    //                    config.Socket.Close();
    //                }

    //            }

    //            var lst = cacheRemotePoint.TryGetValue(port);

    //            foreach (var item in lst)
    //            {
    //                item.Value.Close();
    //            }
    //        }
    //    }

    //    public ITransfer ConnectTo(int localPort, IPEndPoint remotePoint, int maxLengthPerDataPack)
    //    {
    //        var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

    //        socket.Bind(new IPEndPoint(remotePoint.Address, localPort));

    //        try
    //        {
    //            var tempBuff = bufferManager.TakeBuffer(maxLengthPerDataPack);

    //            EndPoint tempRemotePoint = null;

    //            var par = new UdpReceiveParam();
    //            par.Buffer = tempBuff;
    //            par.socket = socket;
    //            par.InitMaxLengthPerDataPack = maxLengthPerDataPack;

    //            par.socket.BeginReceiveFrom(tempBuff, 0, par.InitMaxLengthPerDataPack, SocketFlags.None, ref tempRemotePoint, null, par);
    //        }
    //        catch (Exception)
    //        {
    //            return null;
    //        }

    //        var trans = new UDPTransferInternal(socket, maxLengthPerDataPack, remotePoint);

    //        trans.TransferClosed += OnTransferClosed;

    //        cacheRemotePoint.Add(localPort, remotePoint, trans);

    //        return trans;

    //    }

    //    public void SendBroadcastData(ArraySegment<byte> data)
    //    {
    //        SendBroadcastData(data.Array, data.Offset, data.Count);
    //    }

    //    public void SendBroadcastData(byte[] data, int offset, int count)
    //    {
    //        //if (_broadcastTransfer==null)
    //        //{
    //        //    lock (lockerObj)
    //        //    {
    //        //        if (_broadcastTransfer==null)
    //        //        {
    //        //            _broadcastTransfer=new UDPBroadcast(_broadcastPort,0);
    //        //            //_broadcastSocket=new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
    //        //            //_broadcastSocket.Bind(new IPEndPoint(IPAddress.Any,0));
    //        //            //_broadcastTransfer=new UDPTransfer(_broadcastSocket,8192,1024*1024);
    //        //            _broadcastTransfer.AfterReceiveData += BroadcastDataReceived;
    //        //        }
    //        //    }
    //        //}

    //        //_broadcastTransfer.SendAsyn(data, offset,count);

    //    }

    //    /// <summary>
    //    ///     当udp端口有数据进入的时候,引发该事件,用于判断是否处理该远程端口
    //    /// </summary>
    //    public event EventHandler<RemoteRequestPointConnectEventArgs> ConnectRequest;

    //    /// <summary>
    //    ///     当确认该远程端点为可以处理后,引发该函数
    //    /// </summary>
    //    public event EventHandler<RemoteConenctSuccessEventArgs> ConnectSuccessed;

    //    public event EventHandler<DataReceiveEventArgs> BroadcastDataReceived;

    //    private void OnDataReceive(IAsyncResult iar)
    //    {
    //        Exception error = null;
    //        int receiveCount = 0;
    //        EndPoint rp = null;

    //        var par = (UdpReceiveParam)iar.AsyncState;

    //        try
    //        {
    //            receiveCount = par.socket.EndReceiveFrom(iar, ref rp);
    //        }
    //        catch (Exception ex)
    //        {
    //            error = ex;
    //        }

    //        var revBuffer = par.Buffer;
    //        var localPort = ((IPEndPoint)par.socket.LocalEndPoint).Port;

    //        if (!isClosed)
    //        {
    //            var tempBuff = bufferManager.TakeBuffer(par.InitMaxLengthPerDataPack);

    //            EndPoint tempRemotePoint = null;

    //            par.Buffer = tempBuff;

    //            par.socket.BeginReceiveFrom(tempBuff, 0, par.InitMaxLengthPerDataPack, SocketFlags.None, ref tempRemotePoint, null, par);
    //        }

    //        try
    //        {
    //            if (rp != null || receiveCount > 0)
    //            {
    //                UDPTransferInternal transfer = null;

    //                if (cacheRemotePoint.ContainsKey(localPort, rp))
    //                {
    //                    transfer = cacheRemotePoint[localPort, rp];
    //                }
    //                else
    //                {
    //                    transfer = new UDPTransferInternal(par.socket, par.InitMaxLengthPerDataPack, (IPEndPoint)rp);
    //                    if (OnAcceptedConnect((IPEndPoint)rp, transfer))
    //                    {
    //                        cacheRemotePoint.Add(localPort, rp, transfer);

    //                        transfer.TransferClosed += OnTransferClosed;

    //                        OnConnectSuccess(transfer);

    //                    }
    //                }

    //                if (transfer != null)
    //                {
    //                    transfer.OnDataReceive(new ArraySegment<byte>(revBuffer, 0, receiveCount), error);
    //                }
    //            }
    //        }
    //        catch (Exception)
    //        {
    //        }
    //        finally
    //        {
    //            bufferManager.ReturnBuffer(revBuffer);
    //        }



    //    }

    //    private bool OnAcceptedConnect(IPEndPoint remotePoint, ITransfer transfer)
    //    {


    //        var e = new RemoteRequestPointConnectEventArgs(remotePoint, transfer);

    //        var isEnabledConnect = false;
    //        if (ConnectRequest != null)
    //        {
    //            var delList = ConnectRequest.GetInvocationList();

    //            if (delList.Length > 0)
    //            {
    //                for (int i = 0; i < delList.Length; i++)
    //                {
    //                    try
    //                    {
    //                        ((EventHandler<RemoteRequestPointConnectEventArgs>)delList[i]).Invoke(this, e);
    //                    }
    //                    catch (Exception)
    //                    {
    //                        continue;
    //                    }
    //                }

    //                isEnabledConnect = e.IsEnableConnect;
    //            }
    //        }



    //        return isEnabledConnect;
    //    }

    //    private void OnConnectSuccess(ITransfer transfer)
    //    {
    //        var e = new RemoteConenctSuccessEventArgs(transfer);

    //        if (ConnectSuccessed != null)
    //        {
    //            var delList = ConnectSuccessed.GetInvocationList();

    //            if (delList.Length > 0)
    //            {
    //                for (int i = 0; i < delList.Length; i++)
    //                {
    //                    try
    //                    {
    //                        ((EventHandler<RemoteConenctSuccessEventArgs>)delList[i]).Invoke(this, e);
    //                    }
    //                    catch (Exception)
    //                    {
    //                        continue;
    //                    }
    //                }

    //            }
    //        }


    //    }

    //    private void OnTransferClosed(object sender, TransferClosedEventArgs e)
    //    {
    //        var netTrans = (INetTransfer)e.Transfer;

    //        //if (cacheRemotePoint.ContainsKey(netTrans.LocalPort))
    //        //{
    //        //    lock (cacheRemotePoint)
    //        //    {
    //        netTrans.TransferClosed -= OnTransferClosed;
    //        cacheRemotePoint.Remove(netTrans.LocalPort, netTrans.RemotePoint);
    //        //    }
    //        //}
    //    }



    //    //public void SendTo(ArraySegment<byte> data, IPEndPoint remotePoint)
    //    //{
    //    //    SendTo(data, remotePoint, false);
    //    //}

    //    //public void SendTo(ArraySegment<byte> data, IPEndPoint remotePoint, bool isBroadcast)
    //    //{
    //    //    if (isClosed)
    //    //    {
    //    //        return;
    //    //    }

    //    //    if (isBroadcast)
    //    //    {
    //    //        _socket.SendTo(data.Array, data.Offset, data.Count, SocketFlags.Broadcast, remotePoint);
    //    //    }
    //    //    else
    //    //    {
    //    //        _socket.SendTo(data.Array, data.Offset, data.Count, SocketFlags.None, remotePoint);
    //    //    }

    //    //}

    //    private class UdpSocketConfig
    //    {
    //        public int Port;
    //        public Socket Socket;
    //        public bool EnableSendCheck;
    //        public int InitMaxLengthPerDataPack;
    //        private ITransfer Transfer;
    //    }

    //    private class UdpReceiveParam
    //    {
    //        public byte[] Buffer;
    //        public Socket socket;
    //        public int InitMaxLengthPerDataPack;

    //    }
    //}



    public class UDPFactory : IDisposable
    {
        private Dictionary<int, UDPServer> cacheServer = new Dictionary<int, UDPServer>(10);
        private object lockerObj = new object();
        private bool _isDisposed = false;

        public void AddPort(int localPort, bool isSendCheck, int maxLengthPerDataPack)
        {
            if (_isDisposed)
            {
                return;
            }

            UDPServer server = cacheServer.TryGetValue(localPort);

            if (server == null)
            {
                lock (cacheServer)
                {
                    server = new UDPServer(localPort, maxLengthPerDataPack);
                    server.EnableSendCheck = isSendCheck;
                    server.ConnectRequest += ConnectRequest;
                    server.ConnectSuccessed += ConnectSuccessed;

                    cacheServer.Add(localPort, server);
                }
            }
        }

        public void RemovePort(int port)
        {
            UDPServer server = cacheServer.TryGetValue(port);

            if (server != null)
            {
                server.Dispose();
            }
        }

        public ITransfer ConnectToBroadcast(int localPort, int remotePort, int maxLengthPerDataPack)
        {
            var server = cacheServer.TryGetValue(localPort);

            if (server == null)
            {
                lock (lockerObj)
                {
                    server = cacheServer.TryGetValue(localPort);

                    if (server == null)
                    {
                        server = new UDPServer(localPort, maxLengthPerDataPack);
                        cacheServer.Add(localPort, server);
                    }
                }
            }

            return server.ConnectToBroadcast(remotePort);
        }

        public ITransfer ConnectTo(int localPort, IPEndPoint remotePoint, bool isSendCheck, int maxLengthPerDataPack)
        {
            var server = cacheServer.TryGetValue(localPort);

            if (server == null)
            {
                lock (lockerObj)
                {
                    server = cacheServer.TryGetValue(localPort);

                    if (server == null)
                    {
                        server = new UDPServer(localPort, maxLengthPerDataPack);
                        server.EnableSendCheck = isSendCheck;
                        cacheServer.Add(localPort, server);
                    }
                }
            }

            return server.ConnectTo(remotePoint, isSendCheck);
        }

        public void Close()
        {
            lock (lockerObj)
            {
                foreach (var udpServer in cacheServer)
                {
                    udpServer.Value.Dispose();
                }

                _isDisposed = true;

                cacheServer.Clear();
            }
        }

        #region Implementation of IDisposable

        public void Dispose()
        {
            if (!_isDisposed)
            {
                lock (lockerObj)
                {
                    if (!_isDisposed)
                    {
                        _isDisposed = true;
                        Close();
                    }
                }
            }
        }

        #endregion

        /// <summary>
        ///     当有远程TCP申请链接时
        /// </summary>
        public event EventHandler<RemoteRequestConnectEventArgs> ConnectRequest;

        /// <summary>
        ///     当成功连接后引发该事件
        /// </summary>
        public event EventHandler<RemoteConenctSuccessEventArgs> ConnectSuccessed;


    }

    public class UDPServer : IDisposable
    {
        private int _localPort = 0;
        private Socket _socket = null;
        private int _maxLengthPerDataPack = 1024;
        private Dictionary<IPEndPoint, INetTransfer> cacheTransfer = new Dictionary<IPEndPoint, INetTransfer>(10);
        private Dictionary<int,UDPConnectRequestInfo> cacheConnectInfo=new Dictionary<int,UDPConnectRequestInfo>();
        private object lockerObj = new object();
        private BufferManager bufferManager = null;
        private bool _isClosed = false;


        public UDPServer(int localPort, int maxLengthPerDataPack)
        {
            _localPort = localPort;
            _maxLengthPerDataPack = maxLengthPerDataPack + 100;
            bufferManager = BufferManager.CreateBufferManager(_maxLengthPerDataPack * 100,
                                                              _maxLengthPerDataPack + 100);

            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            socket.Bind(new IPEndPoint(IPAddress.Any, _localPort));

            var tempBuff = bufferManager.TakeBuffer(_maxLengthPerDataPack);
            EndPoint tempEndPoint = new IPEndPoint(IPAddress.Any, 0);
            _socket = socket;
            socket.BeginReceiveFrom(tempBuff, 0, _maxLengthPerDataPack, SocketFlags.None, ref tempEndPoint, OnDataReceive, tempBuff);
        }

        public UDPServer(Socket socket, int localPort, int maxLengthPerDataPack)
        {
            _localPort = localPort;
            _maxLengthPerDataPack = maxLengthPerDataPack + 100;
            bufferManager = BufferManager.CreateBufferManager(_maxLengthPerDataPack * 100,
                                                              _maxLengthPerDataPack + 100);

            //var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            //socket.Bind(new IPEndPoint(IPAddress.Any, _localPort));

            var tempBuff = bufferManager.TakeBuffer(_maxLengthPerDataPack);
            EndPoint tempEndPoint = null;

            socket.BeginReceiveFrom(tempBuff, 0, _maxLengthPerDataPack, SocketFlags.None, ref tempEndPoint, OnDataReceive, null);
        }

        public ITransfer ConnectTo(IPEndPoint remotePoint,bool isSendCheck)
        {
            INetTransfer trans = null;

            lock (lockerObj)
            {
                trans = cacheTransfer.TryGetValue(remotePoint, null);

                if (trans == null)
                {
                    var tempTrans = new UDPTransferInternal(_socket, _maxLengthPerDataPack, isSendCheck, remotePoint);
                    tempTrans.EnableSendCheck = isSendCheck;
                    tempTrans.TransferClosed += trans_TransferClosed;
                    cacheTransfer.Add(remotePoint, tempTrans);
                    trans = tempTrans;
                }

            }



            return trans;
        }

        public ITransfer ConnectToBroadcast(int remotePort)
        {
            INetTransfer trans = null;

            lock (lockerObj)
            {
                var remotePoint = new IPEndPoint(IPAddress.Broadcast, remotePort);

                trans = cacheTransfer.TryGetValue(remotePoint, null);

                if (trans == null)
                {
                    trans = new UDPTransferBroadcastInternal(_socket, remotePort, _maxLengthPerDataPack,this.EnableSendCheck);
                    trans.TransferClosed += trans_TransferClosed;
                    cacheTransfer.Add(remotePoint, trans);
                }
            }

            return trans;
        }

        public void Disconnect(IPEndPoint remotePoint)
        {
            lock (lockerObj)
            {
                INetTransfer trans = null;

                try
                {
                    trans = cacheTransfer.TryGetValue(remotePoint);
                    if (trans != null)
                    {
                        trans.Close();
                    }
                }
                catch (Exception)
                {

                }

                cacheTransfer.Remove(remotePoint);
            }
        }

        public bool EnableSendCheck { set; get; }

        /// <summary>
        ///     当udp端口有数据进入的时候,引发该事件,用于判断是否处理该远程端口
        /// </summary>
        public event EventHandler<RemoteRequestConnectEventArgs> ConnectRequest;

        /// <summary>
        ///     当确认该远程端点为可以处理后,引发该函数
        /// </summary>
        public event EventHandler<RemoteConenctSuccessEventArgs> ConnectSuccessed;

        private void OnDataReceive(IAsyncResult iar)
        {
            Exception error = null;
            int receiveCount = 0;
            EndPoint rp = new IPEndPoint(IPAddress.Any, 0);

            var revBuffer = (byte[])iar.AsyncState;

            try
            {
                receiveCount = _socket.EndReceiveFrom(iar, ref rp);
            }
            catch (Exception ex)
            {
                error = ex;
            }

            if (!_isClosed)
            {
                var tempBuff = bufferManager.TakeBuffer(_maxLengthPerDataPack);

                EndPoint tempRemotePoint = new IPEndPoint(IPAddress.Any, 0);

                _socket.BeginReceiveFrom(tempBuff, 0, _maxLengthPerDataPack, SocketFlags.None, ref tempRemotePoint, OnDataReceive, tempBuff);
            }


            var remotePoint = (IPEndPoint)rp;

            try
            {
                if (receiveCount > 0)
                {
                    if (this.EnableSendCheck)
                    {
                        if (receiveCount<7)
                        {
                            return;
                        }

                        var bagID = BitConverter.ToInt32(revBuffer, 0);

                        var config = cacheConnectInfo.TryGetValue(bagID);

                        switch (revBuffer[4])
                        {
                            case 0xF0:
                                {
                                    if (config==null)
                                    {
                                        var transfer = new UDPTransferInternal(_socket, _maxLengthPerDataPack, this.EnableSendCheck, remotePoint);
                                        transfer.EnableSendCheck = this.EnableSendCheck;
                                        if (!OnAcceptedConnect(remotePoint, transfer))
                                        {
                                            return;
                                        }

                                        if (transfer.EnableSendCheck)
                                        {
                                            config=new UDPConnectRequestInfo();

                                            cacheConnectInfo.Add(bagID,config);

                                            getHandShakeResponse(bagID, UDPHandShakeStep.F0_Step1);                                            
                                        }
                                        else
                                        {
                                            cacheTransfer.Add(remotePoint, transfer);

                                            transfer.TransferClosed += OnTransferClosed;

                                            OnConnectSuccess(transfer);
                                        }

                                    }
                                }
                                break;
                            case 0xF1:
                                {
                                    if (config==null)
                                    {
                                        return;
                                    }

                                    getHandShakeResponse(bagID, UDPHandShakeStep.F1_Step2);
                                }
                                break;
                            case 0xF3:
                                {
                                    if (config==null)
                                    {
                                        return;
                                    }

                                    cacheConnectInfo.Remove(bagID);

                                    var transfer = new UDPTransferInternal(_socket, _maxLengthPerDataPack, this.EnableSendCheck, remotePoint);

                                    transfer.RemoteRevBuffer = config.RemoteRevBuffer;

                                    cacheTransfer.Add(remotePoint, transfer);

                                    transfer.TransferClosed += OnTransferClosed;

                                    OnConnectSuccess(transfer);

                                    getHandShakeResponse(bagID, UDPHandShakeStep.F1_Step2);
                                }
                                break;
                            default:
                                return;
                        }

                    }
                    else
                    {
                        

                        var transfer = (UDPTransferInternal)cacheTransfer.TryGetValue(remotePoint, null);

                        if (transfer == null)
                        {
                            lock (lockerObj)
                            {
                                transfer = new UDPTransferInternal(_socket, _maxLengthPerDataPack,this.EnableSendCheck, remotePoint);
                                transfer.EnableSendCheck = this.EnableSendCheck;
                                if (OnAcceptedConnect(remotePoint, transfer))
                                {
                                        cacheTransfer.Add(remotePoint, transfer);

                                        transfer.TransferClosed += OnTransferClosed;

                                        OnConnectSuccess(transfer);
                                }
                            }
                        }

                        if (transfer != null && !transfer.IsStop)
                        {
                            transfer.OnDataReceive(new ArraySegment<byte>(revBuffer, 0, receiveCount), error);
                        }
                    }




                }
            }
            catch (Exception)
            {
            }
            finally
            {
                bufferManager.ReturnBuffer(revBuffer);
            }
        }

        private ArraySegment<byte> getHandShakeResponse(int bagID,UDPHandShakeStep step)
        {
            return default(ArraySegment<byte>);
        }

        private void OnTransferClosed(object sender, TransferClosedEventArgs e)
        {
            var netTrans = (INetTransfer)e.Transfer;

            //if (cacheRemotePoint.ContainsKey(netTrans.LocalPort))
            //{
            //    lock (cacheRemotePoint)
            //    {
            netTrans.TransferClosed -= OnTransferClosed;
            cacheTransfer.Remove(netTrans.RemotePoint);
            //    }
            //}
        }

        private bool OnAcceptedConnect(IPEndPoint remotePoint, ITransfer transfer)
        {


            var e = new RemoteRequestConnectEventArgs(remotePoint, transfer);

            var isEnabledConnect = false;
            if (ConnectRequest != null)
            {
                var delList = ConnectRequest.GetInvocationList();

                if (delList.Length > 0)
                {
                    for (int i = 0; i < delList.Length; i++)
                    {
                        try
                        {
                            ((EventHandler<RemoteRequestConnectEventArgs>)delList[i]).Invoke(this, e);
                        }
                        catch (Exception)
                        {
                            continue;
                        }
                    }

                    isEnabledConnect = e.IsEnableConnect;
                }
            }



            return isEnabledConnect;
        }

        private void OnConnectSuccess(ITransfer transfer)
        {
            var e = new RemoteConenctSuccessEventArgs(transfer);

            if (ConnectSuccessed != null)
            {
                var delList = ConnectSuccessed.GetInvocationList();

                if (delList.Length > 0)
                {
                    for (int i = 0; i < delList.Length; i++)
                    {
                        try
                        {
                            ((EventHandler<RemoteConenctSuccessEventArgs>)delList[i]).Invoke(this, e);
                        }
                        catch (Exception)
                        {
                            continue;
                        }
                    }

                }
            }
        }

        void trans_TransferClosed(object sender, TransferClosedEventArgs e)
        {
            e.Transfer.TransferClosed -= trans_TransferClosed;

            lock (lockerObj)
            {
                var trans = (INetTransfer)e.Transfer;

                if (trans != null)
                {
                    trans.Close();
                }

                cacheTransfer.Remove(trans.RemotePoint);
            }
        }

        #region Implementation of IDisposable

        public void Dispose()
        {
            if (_isClosed)
            {
                return;
            }

            lock (lockerObj)
            {
                if (_isClosed)
                {
                    return;
                }

                _isClosed = true;

                var ar = cacheTransfer.Values;

                foreach (var transfer in ar)
                {
                    transfer.TransferClosed -= trans_TransferClosed;
                    transfer.Dispose();
                }

                bufferManager.Clear();

                //bufferManager = null;

                try
                {
                    _socket.Shutdown(SocketShutdown.Both);

                }
                catch (Exception)
                {
                }
                finally
                {
                    _socket.Close();
                }

                
            }
        }

        #endregion

        private class UDPConnectRequestInfo
        {
            public IPEndPoint RemotePoint;
            public int RemoteRevBuffer;
            public UDPHandShakeStep Step;
            public DateTime LastRevResponse;
        }

        private enum UDPHandShakeStep:byte
        {
            F0_Step1=0xF0,
            F1_Step2=0xF1,
            F2_Step3=0xF2
        }
    }

    internal class UDPTransferInternal : UDPTransfer
    {
        //private Socket _socket = null;
        //private bool isClosed = false;
        //private EndPoint remotePoint = null;

        public UDPTransferInternal(Socket socket, int receiveDataMaxLength,bool isEnableSendCheck, IPEndPoint remotePoint)
            : base(socket, remotePoint, receiveDataMaxLength, isEnableSendCheck, false, false)
        {
            //_socket = socket;
            //this.remotePoint = remotePoint;
            //RemotePoint = remotePoint;
        }

        //public IPEndPoint RemotePoint { get; private set; }

        internal void OnDataReceive(ArraySegment<byte> data, Exception error)
        {
            //if (isClosed || data == null || data.Array == null || (data.Count <= 0 && error == null))
            //{
            //    return;
            //}

            var decodeData = base.DecodeReceiveData(data.Array, data.Offset, data.Count);

            base.OnReceiveDataInternal(decodeData);

            //base.OnAfterReceiveData(decodeData, error);

            if (decodeData.Array != data.Array && decodeData.Count > 0)
            {
                bufferManager.ReturnBuffer(decodeData.Array);
            }

            bufferManager.ReturnBuffer(data.Array);
        }

        //public override void  Close()
        //{
        //     base.Close();
        //     Events.EventHelper.Raise(UDPTransferClosed,this,new UDPTransferClosedEventArgs(this));
        //}



        //#region Overrides of TransferBase

        //public override void Close()
        //{
        //    isClosed = true;

        //    if (UDPTransferClosed!=null)
        //    {
        //        UDPTransferClosed(this,new UDPTransferClosedEventArgs(this));
        //    }
        //}

        //private int _receiveBufferCount = 8049;
        //public override int ReceiveBufferCount
        //{
        //    set
        //    {
        //        if (value <= 0)
        //        {
        //            throw new ArgumentOutOfRangeException(@"value");
        //        }

        //        Interlocked.Exchange(ref _receiveBufferCount, value);
        //    }
        //    get { return _receiveBufferCount; }

        //}

        //public override bool IsActivity
        //{
        //    get { return !isClosed; }
        //}

        //protected override void SendDataAsync(byte[] sendStruct, int offset, int count)
        //{
        //    if (isClosed)
        //    {
        //        return;
        //    }

        //    try
        //    {
        //        _socket.SendTo(sendStruct, offset, count, SocketFlags.None, remotePoint);
        //    }
        //    catch (Exception)
        //    {

        //        throw;
        //    }
        //}

        //#endregion

    }

    internal class UDPTransferBroadcastInternal : UDPTransferInternal
    {
        private IPEndPoint _remotePoint;

        public UDPTransferBroadcastInternal(Socket socket, int remotePort, int receiveDataMaxLength, bool isEnableSendCheck)
            : base(socket, receiveDataMaxLength,isEnableSendCheck, null)
        {
            _remotePoint = new IPEndPoint(IPAddress.Broadcast, remotePort);
            //_socket = socket;
            //this.remotePoint = remotePoint;
            //RemotePoint = remotePoint;
        }

        protected override void SendDataAsync(byte[] sendStruct, int offset, int count, EventHandler<DataAfterSendEventArgs> eventHandler, object state)
        {
            _socket.SendTo(sendStruct, offset, count, SocketFlags.Broadcast, _remotePoint);
            //base.SendDataAsync(sendStruct, offset, count);
        }
    }



    //public class UDPBroadcast : TransferBase
    //{
    //    private Socket _socket;
    //    private BufferManager bufferManager = null;
    //    private bool _isClosed = false;
    //    private IPEndPoint _broadcastEndPoint = null;
    //    private bool _isOwner = false;
    //    private int _localSendedBroadcastPort = 0;

    //    private UDPBroadcast()
    //    {
    //        bufferManager = BufferManager.CreateBufferManager(8192, 8192 * 1000);
    //        //var buffer = bufferManager.TakeBuffer(8192);
    //        //EndPoint remotePoint = null;

    //        //_socket.BeginReceiveFrom(buffer, 0, 8192, SocketFlags.Broadcast, ref remotePoint, OnDataReceive, buffer);
    //    }

    //    public UDPBroadcast(int remotebroadcastPort, int localSendedBroadcastPort, bool isOwner)
    //        : this()
    //    {
    //        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    //        _socket.Bind(new IPEndPoint(IPAddress.Any, localSendedBroadcastPort));
    //        _localSendedBroadcastPort = localSendedBroadcastPort;
    //        _broadcastEndPoint = new IPEndPoint(IPAddress.Broadcast, remotebroadcastPort);
    //        _isOwner = isOwner;
    //        BeginReceiveData();
    //    }

    //    public UDPBroadcast(Socket socket, int remotebroadcastPort, int localSendedBroadcastPort, bool isOwner)
    //        : this()
    //    {
    //        _socket = socket;
    //        _localSendedBroadcastPort = localSendedBroadcastPort;
    //        _broadcastEndPoint = new IPEndPoint(IPAddress.Broadcast, remotebroadcastPort);
    //        _isOwner = isOwner;
    //        BeginReceiveData();

    //    }

    //    protected override void OnClose()
    //    {
    //        if (_isClosed)
    //        {
    //            return;
    //        }

    //        if (_isOwner)
    //        {
    //            try
    //            {
    //                _socket.Shutdown(SocketShutdown.Both);

    //            }
    //            catch (Exception)
    //            {

    //            }
    //            finally
    //            {
    //                _isClosed = true;
    //                _socket.Close();
    //            }

    //        }
    //    }

    //    public override int ReceiveBufferCount { get; set; }

    //    public override bool IsActivity
    //    {
    //        get { return true; }
    //    }

    //    protected override void SendDataAsync(byte[] sendStruct, int offset, int count)
    //    {
    //        _socket.SendTo(sendStruct, offset, count, SocketFlags.Broadcast, _broadcastEndPoint);
    //    }


    //    private void OnDataReceive(IAsyncResult iar)
    //    {
    //        EndPoint remotePoint = null;
    //        Exception error = null;
    //        int receiveCount = 0;

    //        try
    //        {
    //            receiveCount = _socket.EndReceiveFrom(iar, ref remotePoint);
    //        }
    //        catch (Exception ex)
    //        {
    //            error = ex;
    //            //return;
    //        }

    //        if (!_isClosed)
    //        {
    //            BeginReceiveData();
    //        }

    //        if (receiveCount > 0)
    //        {
    //            var revedBuffer = (byte[])iar.AsyncState;
    //            base.OnAfterReceiveData(new ArraySegment<byte>(revedBuffer, 0, receiveCount), error);
    //            //Events.EventHelper.Raise(BroadcastDataReceive,this,new DataReceiveEventArgs(new ArraySegment<byte>(revedBuffer,0,receiveCount),null ));
    //        }


    //    }

    //    private void BeginReceiveData()
    //    {
    //        var buffer = bufferManager.TakeBuffer(8192);
    //        EndPoint remotePoint = null;

    //        _socket.BeginReceiveFrom(buffer, 0, 8192, SocketFlags.Broadcast, ref remotePoint, OnDataReceive, buffer);
    //    }
    //}

}
